using System;
using Jalal.Library.Data;
using System.Data;
using BCGC.DAL;
using Jalal.Library.Web;
using Jalal.Library.Utility;
using System.Data.SqlTypes;
using Jalal.Library.Mail;
using System.Collections.Specialized;
using BCGC.BLL.Helper;
using Jalal.Library.DataStructure;
using System.Collections.Generic;
using System.Web;

namespace BCGC.BLL.BusinessObject.UserAccount
{
    public class SiteUser : UserBase
    {
        public override bool IsAdmin
        {
            get { return false; }
        }

        protected UserRole role;
        public UserRole Role
        {
            get { return role; }
            set { role = value; }
        }

        protected bool isOnline;
        public bool IsOnline
        {
            get { return isOnline; }
            set { isOnline = value; }
        }

        protected bool isLocked;
        public bool IsLocked
        {
            get { return isLocked; }
            set { isLocked = value; }
        }

        protected bool isActivated;
        public bool IsActivated
        {
            get { return isActivated; }
        }

        protected string verificationCode;
        public string VerificationCode
        {
            get { return verificationCode; }
        }

        protected string secretQuestion;
        public string SecretQuestion
        {
            get { return secretQuestion; }
            set { secretQuestion = value; }
        }

        protected string secretAnswer;
        public string SecretAnswer
        {
            get { return secretAnswer; }
            set { secretAnswer = value; }
        }

        private UserProfile userProfile;
        public UserProfile Profile
        {
            get { return userProfile; }
            set { userProfile = value; }
        }

        public SiteUser()
        {
            this.id = 0;
            this.username = string.Empty;
            this.password = string.Empty;
            this.email = string.Empty;
            this.createDateTime = SqlDateTime.MinValue.Value;
            this.invalidLoginCount = 0;
            this.isLocked = false;
            this.isOnline = false;
            this.lastLoginTime = SqlDateTime.MinValue.Value;
            this.role = null;
            this.secretAnswer = string.Empty;
            this.secretQuestion = string.Empty;
            this.userProfile = null;
            this.verificationCode = string.Empty;
        }

        public SiteUser(DataRow dataRow, bool fullLoad)
        {
            if (dataRow != null)
            {
                if (dataRow.Table.Columns.Contains("UserId"))
                    this.id = (int)CommonUtility.FilterNull(dataRow["UserId"], typeof(int));
                if (dataRow.Table.Columns.Contains("SiteUserName"))
                    this.username = (string)CommonUtility.FilterNull(dataRow["SiteUserName"], typeof(string));
                if (dataRow.Table.Columns.Contains("SiteUserPassword"))
                    this.password = (string)CommonUtility.FilterNull(dataRow["SiteUserPassword"], typeof(string));
                if (dataRow.Table.Columns.Contains("Email"))
                    this.email = (string)CommonUtility.FilterNull(dataRow["Email"], typeof(string));
                if (dataRow.Table.Columns.Contains("CreateDateTime"))
                    this.createDateTime = (DateTime)CommonUtility.FilterNull(dataRow["CreateDateTime"], typeof(DateTime));
                if (dataRow.Table.Columns.Contains("InvalidLoginCount"))
                    this.invalidLoginCount = (int)CommonUtility.FilterNull(dataRow["InvalidLoginCount"], typeof(int));
                if (dataRow.Table.Columns.Contains("IsLocked"))
                    this.isLocked = (bool)CommonUtility.FilterNull(dataRow["IsLocked"], typeof(bool));
                if (dataRow.Table.Columns.Contains("IsOnline"))
                    this.isOnline = (bool)CommonUtility.FilterNull(dataRow["IsOnline"], typeof(bool));
                if (dataRow.Table.Columns.Contains("LastLoginTime"))
                    this.lastLoginTime = (DateTime)CommonUtility.FilterNull(dataRow["LastLoginTime"], typeof(DateTime));
                if (dataRow.Table.Columns.Contains("SecretAnswer"))
                    this.secretAnswer = (string)CommonUtility.FilterNull(dataRow["SecretAnswer"], typeof(string));
                if (dataRow.Table.Columns.Contains("SecretQuestion"))
                    this.secretQuestion = (string)CommonUtility.FilterNull(dataRow["SecretQuestion"], typeof(string));
                if (dataRow.Table.Columns.Contains("VerificationCode"))
                    this.verificationCode = (string)CommonUtility.FilterNull(dataRow["VerificationCode"], typeof(string));

                if (fullLoad)
                {
                    this.userProfile = new UserProfile(dataRow);
                    if (userProfile != null)
                        this.userProfile.UserId = this.id;

                    this.role = new UserRole(dataRow);
                }
                else
                {
                    this.userProfile = null;
                    this.role = null;
                }
            }
            else
            {
                this.id = 0;
                this.username = string.Empty;
                this.password = string.Empty;
                this.email = string.Empty;
                this.createDateTime = SqlDateTime.MinValue.Value;
                this.invalidLoginCount = 0;
                this.isLocked = false;
                this.isOnline = false;
                this.lastLoginTime = SqlDateTime.MinValue.Value;
                this.role = null;
                this.secretAnswer = string.Empty;
                this.secretQuestion = string.Empty;
                this.userProfile = null;
                this.verificationCode = string.Empty;
            }
        }

        private static ReadWriteCustomCollection<SiteUser> LoadFromDataTable(DataTable data)
        {
            ReadWriteCustomCollection<SiteUser> result = new ReadWriteCustomCollection<SiteUser>();

            if (data != null && data.Rows.Count > 0)
            {
                foreach (DataRow row in data.Rows)
                {
                    result.Add(new SiteUser(row,false));
                }
            }
            return result;
        } 

        public override void Login(string username, string password)
        {
            DataFactory.GetDataMiner().BeginTransaction(true);

            password = EncryptPassword(password);
            DataTable data = UserData.GetSiteUserByLoginInfo(username, password);

            DataFactory.GetDataMiner().CommitTransaction();

            if (data != null && data.Rows.Count > 0)
            {
                SiteUser user = new SiteUser(data.Rows[0], false);
                SessionManager.LoggedUser = user;
            }
        }

        public override void Logout()
        {
            SessionManager.LoggedUser = null;
        }

        public static bool SendRegistrationMail(string username, string password, string email, 
            string verificationCode)
        {
            MailSettings mailSettings = Settings.MailSettings;
            Settings settings = Settings.SiteSettings;
            EmailTemplate template = EmailTemplate.GetEmailTemplateById((int)EmailTemplates.RegistrationVerificationMail);

            if (settings != null && template != null)
            {
                NameValueCollection replaceItems = new NameValueCollection();
                replaceItems.Add("Sender", settings.AdminEmail);
                replaceItems.Add("Subject", template.MailSubject);
                replaceItems.Add("[Support]", settings.SupportEmail);
                replaceItems.Add("ReceiverName", username);
                replaceItems.Add("ReceiverEmail", email);
                replaceItems.Add("[Username]", username);
                replaceItems.Add("[SiteUrl]", settings.SiteUrl + CustomSiteMap.VerifyRegistration.Replace("~",string.Empty) + "?vc=" + verificationCode);

                return MailSender.SendTemplatedMaill(mailSettings, HttpContext.Current.Server.HtmlDecode(template.MailBody), replaceItems);
            }
            else
                return false;
        }

        public string Register(string username, string password, string email, string secretQuestion, 
            string secretAnswer)
        {
            DataFactory.GetDataMiner().BeginTransaction(true);

            string verificationCode = Guid.NewGuid().ToString();
            int userId = UserData.CreateNewAccount(username, EncryptPassword(password) , 
                email, secretQuestion, secretAnswer, verificationCode, UserRole.GetDefaultRoleId());

            DataFactory.GetDataMiner().CommitTransaction();

            return verificationCode;
        }

        public static void Delete(List<int> usersToDelete)
        {
            DataFactory.GetDataMiner().BeginTransaction(false);

            try
            {
                int deletedItemCount = UserData.DeleteUsers(usersToDelete);
                if (deletedItemCount == usersToDelete.Count)
                    DataFactory.GetDataMiner().CommitTransaction();
                else
                    throw new Exception("Failed to delete all items");
            }
            catch (Exception ex)
            {
                DataFactory.GetDataMiner().RollBackTransaction();
                throw ex;
            }
        }

        public static ReadWriteCustomCollection<SiteUser> GetAllUsers(int currentPageIndex, string sortOrder, 
            int pageSize, string searchUsername, int? searchRoleId, DateTime? searchRegDateFrom, 
            DateTime? searchRegDateTo, bool? searchActive, bool? searchLocked, out int totalData)
        {
            DataFactory.GetDataMiner().BeginTransaction(true);

            totalData = 0;

            DataTable userData = UserData.GetAllUsers(currentPageIndex, sortOrder, pageSize, searchUsername,
                searchRoleId, searchRegDateFrom, searchRegDateTo, searchActive, searchLocked, out totalData);
            ReadWriteCustomCollection<SiteUser> users = LoadFromDataTable(userData);

            DataFactory.GetDataMiner().CommitTransaction();

            return users;
        }

        public static void UpdateLock(List<int> usersToLock, List<int> usersToUnlock)
        {
            DataFactory.GetDataMiner().BeginTransaction(false);

            try
            {
                int updatedItemCount = UserData.UpdateUserLocks(usersToLock, usersToUnlock);
                if (updatedItemCount == usersToLock.Count + usersToUnlock.Count)
                    DataFactory.GetDataMiner().CommitTransaction();
                else
                    throw new Exception("Failed to update all items");
            }
            catch (Exception ex)
            {
                DataFactory.GetDataMiner().RollBackTransaction();
                throw ex;
            }
        }

        public static bool CheckUsernameTaken(string username)
        {
            DataFactory.GetDataMiner().BeginTransaction(true);

            int count = UserData.GetUserCountByUsername(username);

            DataFactory.GetDataMiner().CommitTransaction();

            return (count > 0);
        }

        public static bool VerifyRegistration(string verificationCode)
        {
            DataFactory.GetDataMiner().BeginTransaction(true);

            int count = UserData.ActivateAccount(verificationCode);

            DataFactory.GetDataMiner().CommitTransaction();

            return (count > 0);
        }

        public static SiteUser GetUserById(int id, bool fullLoad)
        {
            DataFactory.GetDataMiner().BeginTransaction(true);

            DataTable userData = UserData.GetSiteUserByUserId(id);

            DataFactory.GetDataMiner().CommitTransaction();

            if (userData != null && userData.Rows.Count > 0)
            {
                SiteUser user = new SiteUser(userData.Rows[0], fullLoad);
                return user;
            }
            else
                return null;
        }

        public static bool SendPasswordRecoveryMail(string username)
        {
            DataFactory.GetDataMiner().BeginTransaction(true);

            string verificationCode = Guid.NewGuid().ToString();
            string email = UserData.UpdateVerificationCode(username, verificationCode);

            DataFactory.GetDataMiner().CommitTransaction();

            MailSettings mailSettings = Settings.MailSettings;
            Settings settings = Settings.SiteSettings;
            EmailTemplate template = EmailTemplate.GetEmailTemplateById((int)EmailTemplates.PasswordRecoveryMail);

            if ( !string.IsNullOrEmpty(email) && settings != null && template != null)
            {
                NameValueCollection replaceItems = new NameValueCollection();
                replaceItems.Add("Sender", settings.AdminEmail);
                replaceItems.Add("Subject", template.MailSubject);
                replaceItems.Add("[Support]", settings.SupportEmail);
                replaceItems.Add("ReceiverName", username);
                replaceItems.Add("ReceiverEmail", email);
                replaceItems.Add("[Username]", username);
                replaceItems.Add("[SiteUrl]", settings.SiteUrl + CustomSiteMap.RecoverPassword.Replace("~", string.Empty) + "?vc=" + verificationCode);

                return MailSender.SendTemplatedMaill(mailSettings, HttpContext.Current.Server.HtmlDecode(template.MailBody), replaceItems);
            }
            else
                return false;
        }

        public bool Update(bool updateFull)
        {
            DataFactory.GetDataMiner().BeginTransaction(false);
            bool result = false;
            try
            {
                if (updateFull)
                {
                    result = (UserData.UpdateUserAccount(this.Id, EncryptPassword(this.Password),
                        this.Email, this.SecretQuestion, this.SecretAnswer) > 0 && this.Profile.Update());

                }
                else
                {
                    result = UserData.UpdateUserAccount(this.Id, EncryptPassword(this.Password),
                        this.Email, this.SecretQuestion, this.SecretAnswer) > 0;
                }
                DataFactory.GetDataMiner().CommitTransaction();
                return result;
            }
            catch (Exception ex)
            {
                DataFactory.GetDataMiner().RollBackTransaction();
                throw ex;
            }
        }
    }
}
